/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package analiseSintatica.Regras.Comandos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;
import analiseSintatica.Regras.Expressoes.RegraExpressao;
import analiseSintatica.estruturadados.ErroSintatico;
import analiseSintatica.estruturadados.NoArvore;

import java.util.LinkedList;

/**
 *
 * @author Edney
 */
public class RegraDoWhile extends Regra {

    protected static Regra instancia;

    protected String estrutura = "do <bloco> while '(' <expressao> ')' ';'";
    
    /**
     * Construtor privado necessario ao singleton
     */
    private RegraDoWhile() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraDoWhile getInstance() {
        if (instancia == null) {
            instancia = new RegraDoWhile();
        }
        return (RegraDoWhile) instancia;
    }

    

    @Override
    public NoArvore analisar(LinkedList<LinkToken> tokens) throws ErroSintaticoException {
    	ErroSintaticoException erros = new ErroSintaticoException();

        NoArvore naoterminaldowhile = new NoArvore("<do_while>", false);
        naoterminaldowhile.adicionaFilho(reconhecerDo(tokens));
        
        try {
        	naoterminaldowhile.adicionaFilho(RegraBloco.getInstance().analisar(tokens));
        } catch (ErroSintaticoException e) {
            while (e.size() != 0) {
                erros.addErros(e.getErros());
            }
        }
        
        try {
            naoterminaldowhile.adicionaFilho(reconheceToken(tokens, "while",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = RegraExpressao.getInstance().getPrimeiro();
            LinkedList<String> parentese = new LinkedList<String>();
            parentese.add("(");
            sincronizacao = getUniao(sincronizacao, parentese);
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
        }

        try {
        	naoterminaldowhile.adicionaFilho(reconheceLexema(tokens, "delimitador", "(",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = RegraExpressao.getInstance().getPrimeiro();
            LinkedList<String> parentese = new LinkedList<String>();
            parentese.add("(");
            sincronizacao = getUniao(sincronizacao, parentese);
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
            if (tokens.getFirst().getToken().equals("delimitador") && tokens.getFirst().getLexema().equals("(")) {
                tokens.removeFirst();
            }
        }
        
        try {
        	naoterminaldowhile.adicionaFilho( RegraExpressao.getInstance().analisar(tokens));
        } catch (ErroSintaticoException e) {
            while (e.size() != 0) {
                erros.addErros(e.getErros());
            }
        }

        try {
        	naoterminaldowhile.adicionaFilho(reconheceLexema(tokens, "delimitador", ")",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = new LinkedList<String>();
            sincronizacao.add(")");
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
            if (tokens.getFirst().getToken().equals("delimitador") && tokens.getFirst().getLexema().equals(")")) {
                tokens.removeFirst();
            }
        }

        try {
        	naoterminaldowhile.adicionaFilho(reconheceLexema(tokens, "delimitador", ";",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = this.getSeguinte();
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
            if (tokens.getFirst().getToken().equals("delimitador") && tokens.getFirst().getLexema().equals(";")) {
                tokens.removeFirst();
            }
        }

        if (erros.size() != 0) {
            throw erros;
        }

        return naoterminaldowhile;
    }

    /**
     * Reconhece terminal "do"
     * @param tokens - Tokens do codigo
     * @return - Sub-arvore sintatica
     */
    public NoArvore reconhecerDo(LinkedList<LinkToken> tokens) {
        tokens.removeFirst();
        return new NoArvore("do", true);
    }

    protected void setPrimeiro() {
        this.primeiro.add("do");
    }

    protected void setSeguinte() {
    	this.seguinte = RegraCmd.getInstance().getSeguinte();
    }

}
